package com.myproject.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import jakarta.annotation.PreDestroy;

import java.time.Duration;
import java.util.concurrent.ThreadLocalRandom;

@Configuration
public class RedisConfig {

	@Value("${spring.redis.host}")
	private String redisHost;

	@Value("${spring.redis.port}")
	private int redisPort;

	@Value("${spring.redis.password:}")
	private String redisPassword;

	@Value("${spring.redis.database:0}")
	private int database;

	// 连接池参数外部化（示例值，按需调整）
	@Value("${spring.redis.lettuce.pool.max-active:64}")
	private int maxActive;
	@Value("${spring.redis.lettuce.pool.min-idle:10}")
	private int minIdle;

	// 高可用配置（按需启用）
	@Value("${spring.redis.sentinel.nodes:}")
	private String sentinelNodes;
	@Value("${spring.redis.sentinel.master:}")
	private String sentinelMaster;

	// --- Redis 核心配置 ---
	@Bean
	public RedisConnectionFactory redisConnectionFactory() {
		RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
		config.setHostName(redisHost);
		config.setPort(redisPort);
		if (StringUtils.hasText(redisPassword)) {
			config.setPassword(redisPassword);
		}
		config.setDatabase(database);

		LettuceConnectionFactory factory = new LettuceConnectionFactory(config);
		factory.afterPropertiesSet(); // 显式初始化
		return factory;
	}

	@Bean
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
		RedisTemplate<String, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(factory);
		template.setKeySerializer(new StringRedisSerializer());
		template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
		template.setHashKeySerializer(new StringRedisSerializer());
		template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
		template.afterPropertiesSet();
		return template;
	}

	@Bean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
		return new StringRedisTemplate(factory); // 简化创建
	}

	// --- 缓存管理（防雪崩/穿透）---
	@Bean
	public CacheManager cacheManager(RedisConnectionFactory factory) {
		// 基础配置 + 随机TTL防雪崩 + 空值防护
		RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(Duration.ofMinutes(30).plusSeconds(ThreadLocalRandom.current().nextInt(120))) // 随机抖动
				.serializeKeysWith(
						RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
				.serializeValuesWith(RedisSerializationContext.SerializationPair
						.fromSerializer(new GenericJackson2JsonRedisSerializer()))
				.disableCachingNullValues(); // 防穿透

		return RedisCacheManager.builder(factory).cacheDefaults(config).transactionAware().build();
	}

	// --- Redisson 分布式服务 ---
	@Bean(destroyMethod = "shutdown")
	public RedissonClient redissonClient() {
		Config config = new Config();

		// 动态选择连接模式
		if (StringUtils.hasText(sentinelNodes)) {
			configureSentinel(config);
		} else {
			configureSingleServer(config);
		}

		return Redisson.create(config);
	}

	private void configureSingleServer(Config config) {
		SingleServerConfig serverConfig = config.useSingleServer().setAddress("redis://" + redisHost + ":" + redisPort);

		if (StringUtils.hasText(redisPassword)) {
			serverConfig.setPassword(redisPassword);
		}
		serverConfig.setDatabase(database).setConnectionPoolSize(maxActive).setConnectionMinimumIdleSize(minIdle)
				.setIdleConnectionTimeout(15_000) // 15秒空闲超时
				.setConnectTimeout(5000) // 5秒连接超时
				.setTimeout(3000); // 3秒操作超时
	}

	private void configureSentinel(Config config) {
		SentinelServersConfig sentinelConfig = config.useSentinelServers().setMasterName(sentinelMaster)
				.addSentinelAddress(sentinelNodes.split(","));

		if (StringUtils.hasText(redisPassword)) {
			sentinelConfig.setPassword(redisPassword);
		}
		sentinelConfig.setDatabase(database).setMasterConnectionPoolSize(maxActive)
				.setSlaveConnectionPoolSize(maxActive);
	}

	// 安全关闭钩子
	@PreDestroy
	public void destroy() {
		try {
			redissonClient().shutdown();
		} catch (Exception e) {
			// 记录日志但避免中断关闭
		}
	}
}